package modelo.dao;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;

import util.Pair;

import modelo.Impuesto;
import modelo.Material;
import modelo.MaterialServicio;
import modelo.Status;
import modelo.Servicio;
import modelo.Tarea;
import modelo.TareaServicio;
import modelo.TipoServicio;
import modelo.EstadoServicio;

/*
 * Maneja entidades:
 *   - Servicios
 *   - Estado de servicios
 *   - Tipos de servicios
 *   - Tareas por Servicio
 *   - Materiales por Servicio
 */

public class DAOServicios {
	protected HashMap<Integer, Servicio> servicios = new HashMap<Integer, Servicio>();
	protected HashMap<Integer, TipoServicio> tiposServicio = new HashMap<Integer, TipoServicio>();
	protected HashMap<Integer, EstadoServicio> estadosServicio = new HashMap<Integer, EstadoServicio>();
	protected HashMap<Pair<Integer, Integer>, TareaServicio> tareasServicio = new HashMap<Pair<Integer, Integer>, TareaServicio>();
	protected HashMap<Pair<Integer, Integer>, MaterialServicio> materialesServicio = new HashMap<Pair<Integer, Integer>, MaterialServicio>();
	
	public void cargarServicios() {
		ResultSet rs = Servidor.consultar(
			"SELECT *\n" +
			"FROM servicio\n"
			);
		
		try {
			while (rs.next()) {
				Servicio e = new Servicio(
					rs.getInt("cod_servicio"),
					rs.getString("descripcion"),
					rs.getString("comentarios"),
					Servidor.impuestos().consultarImpuestoPorCodigo(rs.getInt("cod_impuesto")),
					Servidor.servicios().consultarTipoServicioPorCodigo(rs.getInt("cod_tipo_servicio")),
					Status.valueOf(rs.getInt("status")));
				servicios.put(e.clave(), e);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	public ArrayList<Servicio> consultarServicios() {
		ResultSet rs = Servidor.consultar(
			"SELECT cod_servicio\n" +
			"FROM servicio\n"
			);
		
		return adjuntarServicio(rs);
	}
	
	public ArrayList<Servicio> consultarServiciosPorStatus(Status status) {
		ResultSet rs = Servidor.consultar(
			"SELECT cod_servicio\n" +
			"FROM servicio\n" +
			"WHERE status = " + status.toInt() + "\n"
			);
		
		return adjuntarServicio(rs);
	}
	
	public ArrayList<Servicio> consultarServiciosPorTipo(TipoServicio tipoServicio) {
		ResultSet rs = Servidor.consultar(
			"SELECT cod_servicio\n" +
			"FROM servicio\n" +
			"WHERE cod_tipo_servicio = " + tipoServicio.getCodigo() + "\n"
			);
		
		return adjuntarServicio(rs);
	}
	
	public ArrayList<Servicio> consultarServiciosPorTipoYStatus(TipoServicio tipoServicio, Status status) {
		ResultSet rs = Servidor.consultar(
			"SELECT cod_servicio\n" +
			"FROM servicio\n" +
			"WHERE cod_tipo_servicio = " + tipoServicio.getCodigo() + "\n" +
			"AND status = " + status.toInt() + "\n"
			);
		
		return adjuntarServicio(rs);
	}
	
	public Servicio agregarServicio(String descripcion, String comentarios, Impuesto impuesto, TipoServicio tipoServicio, Status status) {
		try {
			ResultSet rs = Servidor.consultar(
					"INSERT INTO servicio\n" +
					"    (descripcion, comentarios, cod_impuesto, cod_tipo_servicio, status)\n" +
					"VALUES\n" +
					"    ('" + descripcion + "', '" + comentarios + "', " + impuesto.getCodigo() + ", " + tipoServicio.getCodigo() + ", " + status.toInt() + ")\n" +
					"RETURNING cod_servicio"
					);
				
			if (!rs.next()) return null;
			
			Servicio e = new Servicio(rs.getInt("cod_servicio"), descripcion, comentarios, impuesto, tipoServicio, status);
			servicios.put(e.clave(), e);
			
			return e;
		} catch (SQLException e) {
			e.printStackTrace();
			return null;
		}
	}
	
	public Servicio modificarServicio(Servicio servicio) {
		boolean b = Servidor.ejecutar(
			"UPDATE servicio\n" +
			"SET descripcion = '" + servicio.getDescripcion() + "',\n" +
			"    comentarios = '" + servicio.getComentarios() + "',\n" +
			"    cod_impuesto = " + servicio.getImpuesto().getCodigo() + ",\n" +
			"    cod_tipo_servicio = " + servicio.getTipoServicio().getCodigo() + ",\n" +
			"    status = " + servicio.getStatus().toInt() + "\n" +
			"WHERE cod_servicio = '" + servicio.getCodigo() + "'\n"
			);
		
		if (!b) return null;
		
		return servicio;
	}
	
	

	public Servicio consultarServicioPorCodigo(int codigo) {
		return servicios.get(codigo);
	}
	
	private ArrayList<Servicio> adjuntarServicio(ResultSet rs) {
		ArrayList<Servicio> lst = new ArrayList<Servicio>();
		
		try {
			while (rs.next())
				lst.add(servicios.get(rs.getInt("cod_servicio")));
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		return lst;
	}
	
	public void cargarTiposServicio() {
		ResultSet rs = Servidor.consultar(
			"SELECT *\n" +
			"FROM tipo_servicio\n"
			);
		
		try {
			while (rs.next()) {
				TipoServicio e = new TipoServicio(
						rs.getInt("cod_tipo_servicio"),
						rs.getString("descripcion"),
						Status.valueOf(rs.getInt("status")));
				tiposServicio.put(e.clave(), e);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	public ArrayList<TipoServicio> consultarTiposServicio() {
		ResultSet rs = Servidor.consultar(
			"SELECT cod_tipo_servicio\n" +
			"FROM tipo_servicio\n"
			);
		
		return adjuntarTipoServicio(rs);
	}

	public TipoServicio consultarTipoServicioPorCodigo(int codigo) {
		return tiposServicio.get(codigo);
	}
	
	private ArrayList<TipoServicio> adjuntarTipoServicio(ResultSet rs) {
		ArrayList<TipoServicio> lst = new ArrayList<TipoServicio>();
		
		try {
			while (rs.next())
				lst.add(tiposServicio.get(rs.getInt("cod_tipo_servicio")));
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		return lst;
	}
	
	public void cargarEstadosServicio() {
		ResultSet rs = Servidor.consultar(
			"SELECT *\n" +
			"FROM estado_servicio\n"
			);
		
		try {
			while (rs.next()) {
				EstadoServicio e = new EstadoServicio(
					rs.getInt("cod_estado_servicio"),
					rs.getString("descripcion"),
					Status.valueOf(rs.getInt("status")));
				estadosServicio.put(e.clave(), e);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	public ArrayList<EstadoServicio> consultarEstadosServicio() {
		ResultSet rs = Servidor.consultar(
			"SELECT cod_estado_servicio\n" +
			"FROM estado_servicio\n"
			);
		
		return adjuntarEstadoServicio(rs);
	}

	public EstadoServicio consultarEstadoServicioPorCodigo(int codigo) {
		return estadosServicio.get(codigo);
	}
	
	private ArrayList<EstadoServicio> adjuntarEstadoServicio(ResultSet rs) {
		ArrayList<EstadoServicio> lst = new ArrayList<EstadoServicio>();
		
		try {
			while (rs.next())
				lst.add(estadosServicio.get(rs.getInt("cod_estado_servicio")));
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		return lst;
	}
	
	public void cargarTareasServicio() {
		ResultSet rs = Servidor.consultar(
			"SELECT *\n" +
			"FROM tarea_servicio\n"
			);
		
		try {
			while (rs.next()) {
				TareaServicio e = new TareaServicio(
					Servidor.tareas().consultarTareaPorCodigo(rs.getInt("cod_tarea")),
					consultarServicioPorCodigo(rs.getInt("cod_servicio")));
				tareasServicio.put(e.clave(), e);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	
	public ArrayList<TareaServicio> consultarTareasServicio() {
		ResultSet rs = Servidor.consultar(
			"SELECT cod_servicio, cod_tarea\n" +
			"FROM tarea_servicio\n"
			);
		
		return adjuntarTareaServicio(rs);
	}

	public ArrayList<TareaServicio> consultarTareasPorServicio(int codigoServicio) {
		ResultSet rs = Servidor.consultar(
			"SELECT cod_servicio, cod_tarea\n" +
			"FROM tarea_servicio\n" +
			"WHERE cod_servicio = " + codigoServicio + "\n"
			);

		return adjuntarTareaServicio(rs);
	}

	public TareaServicio consultarTareaServicioPorCodigo(int codigoTarea, int codigoServicio) {
		return tareasServicio.get(new Pair<Integer, Integer>(codigoTarea, codigoServicio));
	}
	
	public TareaServicio agregarTareaServicio(Tarea tarea, Servicio servicio) {
		boolean b = Servidor.ejecutar(
				"INSERT INTO tarea_servicio\n" +
				"    (cod_servicio, cod_tarea)\n" +
				"VALUES\n" +
				"    (" + servicio.getCodigo() + ", " + tarea.getCodigo() + ")\n" 
				);
				
		if (!b) return null;
			
		TareaServicio e = new TareaServicio(tarea, servicio);
		tareasServicio.put(e.clave(), e);
			
		return e;
	}

	public boolean eliminarTareasPorServicio(int codigoServicio) {
		boolean b = Servidor.ejecutar(
			"DELETE FROM tarea_servicio\n" +
			"WHERE cod_servicio = " + codigoServicio + "\n"
			);

		return b;
	}

	private ArrayList<TareaServicio> adjuntarTareaServicio(ResultSet rs) {
		ArrayList<TareaServicio> lst = new ArrayList<TareaServicio>();
		
		try {
			while (rs.next())
				lst.add(tareasServicio.get(new Pair<Integer, Integer>(rs.getInt("cod_tarea"), rs.getInt("cod_servicio"))));
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		return lst;
	}
	

	public void cargarMaterialesServicio() {
		ResultSet rs = Servidor.consultar(
			"SELECT *\n" +
			"FROM material_servicio\n"
			);
		
		try {
			while (rs.next()) {
				MaterialServicio e = new MaterialServicio(
					Servidor.materiales().consultarMaterialPorCodigo(rs.getInt("cod_material")),
					consultarServicioPorCodigo(rs.getInt("cod_servicio")),
					rs.getDouble("cantidad"));
				materialesServicio.put(e.clave(), e);
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}
	
	public ArrayList<MaterialServicio> consultarMaterialesServicio() {
		ResultSet rs = Servidor.consultar(
			"SELECT cod_servicio, cod_material\n" +
			"FROM material_servicio\n"
			);
		
		return adjuntarMaterialServicio(rs);
	}

	public ArrayList<MaterialServicio> consultarMaterialesPorServicio(int codigoServicio) {
		ResultSet rs = Servidor.consultar(
			"SELECT cod_servicio, cod_material\n" +
			"FROM material_servicio\n" +
			"WHERE cod_servicio = " + codigoServicio + "\n"
			);

		return adjuntarMaterialServicio(rs);
	}

	public MaterialServicio consultarMaterialServicioPorCodigo(int codigoServicio, int codigoTarea) {
		return materialesServicio.get(new Pair<Integer, Integer>(codigoServicio, codigoTarea));
	}

	public MaterialServicio agregarMaterialServicio(Material material, Servicio servicio, double cantidad) {
		boolean b = Servidor.ejecutar(
				"INSERT INTO material_servicio\n" +
				"    (cod_servicio, cod_material, cantidad)\n" +
				"VALUES\n" +
				"    (" + servicio.getCodigo() + ", " + material.getCodigo() + ", " + cantidad + ")\n" 
				);
			
		if (!b) return null;
		
		MaterialServicio e = new MaterialServicio(material, servicio, cantidad);
		materialesServicio.put(e.clave(), e);
		
		return e;
	}

	private ArrayList<MaterialServicio> adjuntarMaterialServicio(ResultSet rs) {
		ArrayList<MaterialServicio> lst = new ArrayList<MaterialServicio>();
		
		try {
			while (rs.next())
				lst.add(materialesServicio.get(new Pair<Integer, Integer>(rs.getInt("cod_material"), rs.getInt("cod_servicio"))));
		} catch (SQLException e) {
			e.printStackTrace();
		}
		
		return lst;
	}
	
	public boolean eliminarMaterialesPorServicio(int codigoServicio) {
		boolean b = Servidor.ejecutar(
			"DELETE FROM material_servicio\n" +
			"WHERE cod_servicio = " + codigoServicio + "\n"
			);

		return b;
	}
}
